条款06:若不想使用编译器自动生成的函数,就应该明确拒绝

  • 总有些情况,我们不希望编译器为我们生成拷贝构造函数和赋值函数,这时候我们就应该明确告诉编译器不要生成。

  • 为了解决这个问题,我们可以自己写拷贝构造函数和赋值函数,这样编译器就不会为我们生成,但不能写在public里,因为public里的函数可以被外界调用,一种好的方法就是将其写在private或protected里:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    class HomeForSale {
    private:
    HomeForSale(const HomeForSale& house) {
    ...
    }
    HomeForSale& operator= (const HomeForSale& house) {
    ...
    }
    };

    这样做的话编译器就不会为我们生成默认的拷贝构造函数和赋值函数了,又因为我们定义的两个函数是private属性,所以不用担心会在外部会被调用,下面的两条语句是无法编译的:

    1
    2
    HomeForSale house3(house1);
    house2 = house1;
  • 另一方面,如果像上面这种写法,如果类中出现了友元函数或者友元类,它们也可以访问到private下的函数,此时可以将定义换成声明:

    1
    2
    3
    4
    5
    class HomeForSale {
    private:
    HomeForSale(const HomeForSale& house);
    HomeForSale& operator= (const HomeForSale& house);
    };

    这样即使通过编译,链接器也会报错,因为只有声明而没有具体的实现。那么能不能直接把拷贝构造函数和赋值函数声明在public下,只是不实现?这样也是可以的,因为链接器不会放过这个只有空架子的声明而没有具体的实现,但这不是一种好的解决方法,因为编程的一个原则是:错误越早被发现越好,编译要早于链接,所以在编译阶段能发现的错误就不要拖到链接阶段。

  • 总结一下,为了驳回编译器自动生成的函数,有以下两种做法:

    • 将相应的成员函数声明为private且不实现
    • 继承Uncopyable